home *** CD-ROM | disk | FTP | other *** search
- unit PaletteTweaking;
-
- {$ifdef Ver100} { Delphi 3.0x }
- {$define DelphiLessThan4}
- {$endif}
- {$ifdef Ver110} { C++ Builder 3.0x }
- {$define DelphiLessThan4}
- {$endif}
-
- interface
-
- procedure Register;
-
- implementation
-
- uses
- ComCtrls, CommonStuff, ExtCtrls, Menus, SysUtils, Controls,
- Dialogs, Classes, Windows, CommCtrl, Messages, Forms;
-
- type
- TPaletteTweaking = class(TObject)
- private
- FTimer: TTimer;
- FMultilineOption,
- FHotTrackOption,
- FButtonsOption: TMenuItem;
- FOldOnResize: TNotifyEvent;
- {$ifdef DelphiLessThan4}
- FToolsOptions: TMenuItem;
- FOldToolsOptionsOnClick: TNotifyEvent
- {$else}
- FTabPanel: TWinControl; //Component palette's parent
- FOriginalTabPanelHeight: Integer; //Component palette's parent's original height
- {$endif}
- protected
- {$ifdef DelphiLessThan4}
- procedure DoConfigurePaletteClick(Sender: TObject);
- procedure DoIDEResize(Sender: TObject);
- procedure UpdateIDESize(OldRowCount: Integer);
- {$else}
- procedure DoTabResize(Sender: TObject);
- {$endif}
- procedure DoPaletteOptions(Sender: TObject);
- procedure DoTimer(Sender: TObject);
- procedure SetMultiLine(Value: Boolean);
- procedure SetHotTrack(Value: Boolean);
- procedure SetButtons(Value: Boolean);
- public
- destructor Destroy; override;
- procedure Setup;
- procedure TidyUp;
- end;
-
- resourcestring
- SMultiLine = '&Multiline'; //Multiline toggle option
- SHotTrack = '&Hot tracking'; //Hot-tracking toggle option
- SButtons = '&Buttons instead of tabs'; //Tabs as buttons toggle option
-
- const
- SMainFormOnResize = 'WindowResize'; //OnResize handler for main form
- SMsgDlgClass = 'TMessageForm'; //Class name of a MessageDlg form
- //Registry strings
- SRegMultiLine = 'Multi-line Component Palette';
- SRegButtons = 'Tabs As Buttons';
- SRegHotTrack = 'Hot Tracking';
- {$ifdef DelphiLessThan4}
- SRegTabHeight = 'Tab Height';
- SToolsOptions = 'ToolsOptionsItem'; //Tools | Environment Options...
- SToolsOptionsOnClick = 'ToolsOptions'; //OnClick handler for above
- {$else}
- STabPanel = 'PaletteBar';
- {$endif}
-
- destructor TPaletteTweaking.Destroy;
- begin
- TidyUp;
- inherited Destroy
- end;
-
- procedure TPaletteTweaking.Setup;
- {$ifndef DelphiLessThan4}
- var
- Rect: TRect;
- {$endif}
- begin
- //Make sure there is an options menu - bear in mind
- //that the other options code might not be being used
- Stuff.AddOptionsItem;
- //Set up the hot track, multiline and buttons menu items
- FMultilineOption := NewItem(SMultiLine, 0,
- Stuff.Ini.ReadBool(SRegSection, SRegMultiLine,
- Stuff.FTabControl.MultiLine),
- True, DoPaletteOptions, 0, '');
- FHotTrackOption := NewItem(SHotTrack, 0,
- Stuff.Ini.ReadBool(SRegSection, SRegHotTrack,
- Stuff.FTabControl.HotTrack),
- True, DoPaletteOptions, 0, '');
- FButtonsOption := NewItem(SButtons, 0,
- Stuff.Ini.ReadBool(SRegSection, SRegButtons,
- GetWindowLong(Stuff.FTabControl.Handle, gwl_Style) and
- tcs_Buttons <> 0),
- True, DoPaletteOptions, 0, '');
- //All 3 items use the same handler - Tag distinguishes them
- FMultilineOption.Tag := 1;
- FHotTrackOption.Tag := 2;
- FButtonsOption.Tag := 3;
- //Insert the option menu items
- Stuff.FOptions.Add(FMultilineOption);
- Stuff.FOptions.Add(FHotTrackOption);
- Stuff.FOptions.Add(FButtonsOption);
- {$ifdef DelphiLessThan4}
- //To help avoid flickering, we chain into an IDE event handler
- //This may cause problems if someone else chains on to it
- //afterwards, and then we are deleted. The later chainer will
- //be referring to dead code -> AV time
- //Note that we do check to see if the event is already
- //chained and warn the user if so
-
- //Find Tools | Environment Options...
- FToolsOptions := GetComponent(Application.MainForm, SToolsOptions,
- SGenericError + SToolsOptions) as TMenuItem;
- //Save old OnClick handler
- FOldToolsOptionsOnClick := FToolsOptions.OnClick;
- //Warn user if event was already chained
- TestChainedEventHandler(TMethod(FOldToolsOptionsOnClick).Code,
- Application.MainForm.MethodAddress(SToolsOptionsOnClick));
- //Replace Delphi's event handler with our own
- FToolsOptions.OnClick := DoConfigurePaletteClick;
- //Trap IDE form resizing - save old OnResize event
- FOldOnResize := Application.MainForm.OnResize;
- //Warn user if event was already chained
- TestChainedEventHandler(TMethod(FOldOnResize).Code,
- Application.MainForm.MethodAddress(SMainFormOnResize));
- //Replace Delphi's event handler with our own
- Application.MainForm.OnResize := DoResize;
- {$else}
- Stuff.FTabControl.Perform(tcm_GetItemRect, 0, Longint(@Rect));
- FTabPanel := GetComponent(Application.MainForm, STabPanel, SGenericError + STabPanel) as TWinControl;
- FOriginalTabPanelHeight := FTabPanel.Height;
- //Trap component palette resizing - save old OnResize event
- FOldOnResize := Stuff.FTabControl.OnResize;
- //Replace Delphi's event handler with our own
- Stuff.FTabControl.OnResize := DoTabResize;
- {$endif}
-
- //Set the palette properties as dictated by registry
- //This should really be done here, but the multi-line stuff
- //can't manage to make the IDE window larger when
- //Delphi is starting so we do it in a timer event instead
- FTimer := TTimer.Create(nil);
- FTimer.OnTimer := DoTimer;
- FTimer.Interval := 500;
- end;
-
- procedure TPaletteTweaking.Tidyup;
- begin
- //Save option states
- Stuff.Ini.WriteBool(SRegSection, SRegMultiLine, FMultilineOption.Checked);
- Stuff.Ini.WriteBool(SRegSection, SRegHotTrack, FHotTrackOption.Checked);
- Stuff.Ini.WriteBool(SRegSection, SRegButtons, FButtonsOption.Checked);
- //Tidy up timer
- FTimer.Free;
- //Get rid of customisations from IDE
- SetMultiLine(False);
- SetHotTrack(False);
- SetButtons(False);
- //Unchain the chained event handlers
- {$ifdef DelphiLessThan4}
- if Assigned(FToolsOptions) then
- FToolsOptions.OnClick := FOldToolsOptionsOnClick;
- if Assigned(FOldOnResize) then
- Application.MainForm.OnResize := FOldOnResize;
- {$endif}
- if Assigned(FOldOnResize) then
- Stuff.FTabControl.OnResize := FOldOnResize;
- end;
-
- {$ifdef DelphiLessThan4}
- procedure TPaletteTweaking.DoConfigurePaletteClick(Sender: TObject);
- begin
- //To avoid the excess flicker of the multi-line
- //component palette, we'll try turning it off when
- //it would normally flicker
- SetMultiLine(False);
- //Chain onto old OnClick handler
- if (Sender = FToolsOptions) and
- Assigned(FOldToolsOptionsOnClick) then
- FOldToolsOptionsOnClick(Sender);
- //Set back old value
- SetMultiLine(FMultilineOption.Checked);
- end;
-
- procedure TPaletteTweaking.DoIDEResize(Sender: TObject);
- var
- OldRows: Integer;
- begin
- //IDE is being resized - how many tab rows are there right now?
- OldRows := Stuff.FTabControl.Perform(tcm_GetRowCount, 0, 0);
- //Chain onto old OnResize event
- if Assigned(FOldOnResize) then
- FOldOnResize(Sender);
- //Resync component palette's multiline situation
- UpdateIDESize(OldRows);
- end;
- {$else}
- procedure TPaletteTweaking.DoTabResize(Sender: TObject);
- var
- AHeight: Integer;
- begin
- //This was the part that stopped me releasing this for Delphi 4
- //Eventually I found this idea of using Constraints in the GExperts source
- with Sender as TTabControl do
- begin
- AHeight := Height - (DisplayRect.Bottom - DisplayRect.Top) + 29;
- // When compiled in 4.02, this is incompatible with Delphi 4.00/4.01
- Constraints.MinHeight := AHeight;
- Parent.Constraints.MaxHeight := AHeight;
- end
- end;
- {$endif}
-
- procedure TPaletteTweaking.DoPaletteOptions(Sender: TObject);
- begin
- //Toggle options as requested
- with Sender as TMenuItem do
- begin
- Checked := not Checked;
- case Tag of
- 1: SetMultiLine(Checked);
- 2: SetHotTrack(Checked);
- 3: SetButtons(Checked);
- end
- end
- end;
-
- procedure TPaletteTweaking.DoTimer(Sender: TObject);
- begin
- //This triggers shortly after Delphi starts
- //(or whenever this package is initialised)
-
- //Only perform the settings if there is no error
- //message (such as a package load failure). Errors
- //are shown with MessageDlgs which are of type
- //TMessageForm. Let the timer keep running until
- //it's gone so the settings do actually take effect
- if not (Screen.ActiveForm.ClassName = SMsgDlgClass) then
- begin
- FTimer.Enabled := False;
- SetMultiLine(FMultilineOption.Checked);
- SetHotTrack(FHotTrackOption.Checked);
- {$ifndef DelphiLessThan4}
- //Don't need to call this as both the
- //previous routines do it anyway
- SetButtons(FButtonsOption.Checked);
- {$endif}
- end
- end;
-
- {$ifdef DelphiLessThan4}
- procedure TPaletteTweaking.UpdateIDESize(OldRowCount: Integer);
- //Take a number and if necessary, add to it to make it divisible by Inc
- function RoundToNextInc(Current, Inc: Integer): Integer;
- begin
- if Current mod Inc = 0 then
- Result := Current
- else
- Result := Succ(Trunc(Current / Inc)) * Inc
- end;
- var
- RowsDelta: Integer;
- begin
- //If component palette has decided to have a different number of lines then...
- RowsDelta := Stuff.FTabControl.Perform(tcm_GetRowCount, 0, 0) - OldRowCount;
- //Would do this in Delphi 4+ as well, however need to
- //explicitly reset size on a regular basis, since just
- //changing tab page seems to make component palette grow
- if RowsDelta = 0 then Exit;
- //Need more/less room for the tab rows
- Stuff.FTabControl.Height := Stuff.FTabControl.Height +
- RowsDelta * Stuff.Ini.ReadInteger(SRegSection,
- SRegTabHeight, Stuff.FTabControl.TabHeight);
- //Tell main form to resize according to tab control's height
- with Application.MainForm do
- PostMessage(Handle, wm_Size,
- size_Restored, MakeLong(Width, Height));
- end;
- {$endif}
-
- procedure TPaletteTweaking.SetMultiLine(Value: Boolean);
- {$ifdef DelphiLessThan4}
- var
- OldRows: Integer;
- begin
- OldRows := Stuff.FTabControl.Perform(tcm_GetRowCount, 0, 0);
- {$else}
- begin
- {$endif}
- Stuff.FTabControl.MultiLine := Value;
- {$ifdef DelphiLessThan4}
- //If MultiLine property changes, the window gets
- //recreated so we need to set button status back as appropriate
- //since we hacked that option - it ain't a property in Delphi 3
- SetButtons(FButtonsOption.Checked);
- UpdateIDESize(OldRows);
- {$endif}
- end;
-
- procedure TPaletteTweaking.SetHotTrack(Value: Boolean);
- begin
- Stuff.FTabControl.HotTrack := Value;
- {$ifdef DelphiLessThan4}
- //If HotTrack property changes, the window gets
- //recreated so we need to set buttons back as appropriate
- //since we hacked that option - it ain't a property
- SetButtons(FButtonsOption.Checked)
- {$endif}
- end;
-
- procedure TPaletteTweaking.SetButtons(Value: Boolean);
- {$ifdef DelphiLessThan4}
- var
- Style: Longint;
- begin
- //TTabControl/TPageControl doesn't make buttons
- //facility available as a property in Delphi 3
- Style := GetWindowLong(Stuff.FTabControl.Handle, gwl_Style);
- if Value then
- Style := Style or tcs_Buttons
- else
- Style := Style and not tcs_Buttons;
- //Set desired window style
- SetWindowLong(Stuff.FTabControl.Handle, gwl_Style, Style);
- {$else}
- const
- BtnStyle: array[Boolean] of TTabStyle = (tsTabs, tsButtons);
- begin
- Stuff.FTabControl.Style := BtnStyle[Value]
- {$endif}
- end;
-
- var
- PaletteTweakingObject: TPaletteTweaking;
-
- procedure Register;
- begin
- PaletteTweakingObject.Setup
- end;
-
- initialization
- try
- PaletteTweakingObject := TPaletteTweaking.Create
- except
- on E: Exception do
- ShowMessage(SSetupError + ': ' + E.Message)
- end;
- finalization
- PaletteTweakingObject.Free
- end.
-